package org.gm.mybatis.generator.ext;

import java.io.File;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;

import org.gm.mybatis.generator.util.RalationGenerator;
import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.PluginAdapter;
import org.mybatis.generator.api.dom.java.Field;
import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType;
import org.mybatis.generator.api.dom.java.Interface;
import org.mybatis.generator.api.dom.java.JavaVisibility;
import org.mybatis.generator.api.dom.java.Method;
import org.mybatis.generator.api.dom.java.Parameter;
import org.mybatis.generator.api.dom.java.TopLevelClass;
import org.mybatis.generator.api.dom.xml.Attribute;
import org.mybatis.generator.api.dom.xml.Document;
import org.mybatis.generator.api.dom.xml.Element;
import org.mybatis.generator.api.dom.xml.XmlElement;
import org.mybatis.generator.config.CommentGeneratorConfiguration;
import org.mybatis.generator.config.Context;
import org.mybatis.generator.config.TableConfiguration;

public class GeneratorHelper extends PluginAdapter {
	private String baseMapper = null;
	private String serviceProjectPath = null;
	private String baseService = null;
	private String baseServiceImpl = null;
	// Java模型路径
	private String pojoPath = null;
	// sqlmap文件路径
	private String mapperPath = null;
	// mapper接口路径
	private String clientPath = null;

	@Override
	public void initialized(IntrospectedTable introspectedTable) {
		// TODO Auto-generated method stub
		super.initialized(introspectedTable);

	}
	
	@Override
	public void setContext(Context context) {
		super.setContext(context);
		// 设置默认的注释生成器
		CommentGeneratorConfiguration commentCfg = new CommentGeneratorConfiguration();
		commentCfg.setConfigurationType(CommentGeneratorHelper.class.getCanonicalName());
		context.setCommentGeneratorConfiguration(commentCfg);
		
		pojoPath = context.getJavaModelGeneratorConfiguration().getTargetProject()
				.concat("/")
				.concat(context.getJavaModelGeneratorConfiguration().getTargetPackage());
		pojoPath = pojoPath.replace(".", "/");

		mapperPath = context.getSqlMapGeneratorConfiguration().getTargetProject()
				.concat("/")
				.concat(context.getSqlMapGeneratorConfiguration().getTargetPackage());
		mapperPath = mapperPath.replace(".", "/");

		clientPath = context.getJavaClientGeneratorConfiguration().getTargetProject()
				.concat("/")
				.concat(context.getJavaClientGeneratorConfiguration().getTargetPackage());
		clientPath = clientPath.replace(".", "/");

		//删除配置路径下的陈旧文件
		List<TableConfiguration> tl = context.getTableConfigurations();
		for (TableConfiguration tc : tl) {
			String javaName = tc.getDomainObjectName();
			String path = pojoPath.concat("/")
					.concat(javaName)
					.concat(".java");
			File file = new File(path);
			if (file.exists()) {
				System.out.println("[System.out] File Deleting - " + path);
				file.delete();
			}
			
			path = pojoPath.concat("/")
					.concat(javaName)
					.concat("Example.java");
			file = new File(path);
			if (file.exists()) {
				System.out.println("[System.out] File Deleting - " + path);
				file.delete();
			}
			
			path = mapperPath.concat("/")
					.concat(javaName)
					.concat("Mapper.xml");
			file = new File(path);
			if (file.exists()) {
				System.out.println("[System.out] File Deleting - " + path);
				file.delete();
			}
			
			path = clientPath.concat("/")
					.concat(javaName)
					.concat("Mapper.java");
			file = new File(path);
			if (file.exists()) {
				System.out.println("[System.out] File Deleting - " + path);
				file.delete();
			}
		}
	}
	
	public boolean validate(List<String> args) {
		// TODO Auto-generated method stub
		for(String arg:args){
			System.out.println("[System.out] MybatisGenerator Validation Errors.");
			System.out.println("[System.out] " + arg);
		}
		return true;
	}
	
	@Override
	public void setProperties(Properties properties) {
		super.setProperties(properties);
		baseMapper = this.properties.getProperty("baseMapper");
		serviceProjectPath = this.properties.getProperty("serviceProjectPath");
		baseService = this.properties.getProperty("baseService");
		baseServiceImpl = this.properties.getProperty("baseServiceImpl");
	}
	
	@Override
	public boolean sqlMapDocumentGenerated(Document document, IntrospectedTable introspectedTable) {
		// TODO Auto-generated method stub
		super.sqlMapDocumentGenerated(document, introspectedTable);
		XmlElement root = document.getRootElement();
		//默认结果集定义
		XmlElement relationResultMap = new XmlElement("resultMap");
		//基础查询字段定义
		XmlElement baseColumnList = new XmlElement("sql");
		//主键查询定义
		XmlElement selectRelationByPrimaryKey = new XmlElement("select");
		//条件查询定义
		XmlElement selectRelationByExample = new XmlElement("select");
		//带条件的更新语句
		XmlElement updateFromMapByExample = new XmlElement("update");
		for(Element e : root.getElements()){
			if(XmlElement.class.isInstance(e)){
				XmlElement xe = (XmlElement)e;
				if(xe.getAttributes().get(0).getValue().equals("BaseResultMap")){
					relationResultMap.addAttribute(new Attribute("id", "RelationResultMap"));
					relationResultMap.addAttribute(new Attribute("type", introspectedTable.getBaseRecordType()));
					relationResultMap.addAttribute(new Attribute("extends", "BaseResultMap"));
				}
				
				if(xe.getAttributes().get(0).getValue().equals("selectByPrimaryKey")){
					for(Element ae:xe.getElements()){
						selectRelationByPrimaryKey.addElement(ae);
					}
					selectRelationByPrimaryKey.addAttribute(new Attribute("id", "selectRelationByPrimaryKey"));
					selectRelationByPrimaryKey.addAttribute(new Attribute("resultMap", "RelationResultMap"));
					for(Attribute aa:xe.getAttributes()){
						if(aa.getName().equals("parameterType"))selectRelationByPrimaryKey.addAttribute(aa);
					}
				}
				
				if(xe.getAttributes().get(0).getValue().equals("selectByExample")){
					for(Element ae:xe.getElements()){
						selectRelationByExample.addElement(ae);
					}
					selectRelationByExample.addAttribute(new Attribute("id", "selectRelationByExample"));
					selectRelationByExample.addAttribute(new Attribute("resultMap", "RelationResultMap"));
					for(Attribute aa:xe.getAttributes()){
						if(aa.getName().equals("parameterType"))selectRelationByExample.addAttribute(aa);
					}
				}
				
				if(xe.getAttributes().get(0).getValue().equals("updateByExampleSelective")){
					for(Element ae:xe.getElements()){
						updateFromMapByExample.addElement(ae);
					}
					updateFromMapByExample.addAttribute(new Attribute("id", "updateFromMapByExample"));
					updateFromMapByExample.addAttribute(new Attribute("parameterType", "map"));
				}
				
				if(xe.getAttributes().get(0).getValue().equals("Base_Column_List")){
					baseColumnList = xe;
				}
			}
		}
		
		//
		List<XmlElement> extendXml = new LinkedList<XmlElement>();
		
		/**生成关系查询sql**/
		//一对多SQL配置
		List<XmlElement> xml = RalationGenerator.buildManyToOneXML(introspectedTable, relationResultMap, selectRelationByPrimaryKey);
		extendXml.addAll(xml);
		
		//多对一SQL配置
		RalationGenerator.buildOneToManyXML(introspectedTable, relationResultMap);
		
		//多对多SQL配置
		xml = RalationGenerator.buildManyToManyXML(introspectedTable, relationResultMap, selectRelationByPrimaryKey, baseColumnList);
		extendXml.addAll(xml);
		
		if(relationResultMap.getElements().size()>0){
			root.addElement(relationResultMap);
			root.addElement(selectRelationByPrimaryKey);
			root.addElement(selectRelationByExample);
			for(XmlElement xe:extendXml){
				root.addElement(xe);
			}
		}
		root.addElement(updateFromMapByExample);
		
//		final IntrospectedTable table = introspectedTable;
//		final XmlElement root = document.getRootElement();
//		//读取Generator创建的查询语句
//		final StringBuilder selectByPrimaryKey = new StringBuilder();
//		final StringBuilder selectByExample = new StringBuilder();
//		//读取Generator创建的更新语句
//		final StringBuilder updateFromMapByExample = new StringBuilder();
//		//读取当前表的主键字段名称和主键属性名称
//		final StringBuilder primaryColumn = new StringBuilder();
//		final StringBuilder primaryPro = new StringBuilder();
//		for(Element e:root.getElements()){
//			String content = e.getFormattedContent(0);
//			//获取主键查询语句
//			if(content.indexOf("selectByPrimaryKey")==12){
//				selectByPrimaryKey.append(content);
//				String cond = content.substring(content.indexOf("where "));
//				String[] arr = cond.split(" = ");
//				primaryColumn.append(arr[0].substring(6));
//				primaryPro.append(arr[1].substring(2,arr[1].indexOf(",")));
//			}
//			//获取条件查询语句
//			if(content.indexOf("selectByExample")==12){
//				selectByExample.append(content);
//			}
//			//带条件的更新语句
//			if(content.indexOf("updateByExampleSelective")==12){
//				updateFromMapByExample.append(content);
//			}
//		}
		
		//创建各种新的扩展sql操作
//		Element element = new Element() {
//			@Override
//			public String getFormattedContent(int indentLevel) {
//				// TODO Auto-generated method stub
//				//总配置
//				StringBuilder config = new StringBuilder();
//				//resultMap配置
//				StringBuilder resultMap = new StringBuilder();
//				//sql statement配置
//				StringBuilder sqlStatement = new StringBuilder();
//				//自定义条件查询语句
//				StringBuilder cusQuery = new StringBuilder();
//
//				//创建自定义更新语句
//				SqlExtOptional.createUpdateFromMapByExample(updateFromMapByExample);
//				
//				//多对一resultMap配置
//				resultMap.append(RalationGenerator.buildManyToOneResultMap(table, selectByPrimaryKey, primaryColumn, primaryPro, selectByExample));
//				
//				//一对多resultMap配置
//				resultMap.append(RalationGenerator.buildOneToManyResultMap(table, selectByPrimaryKey, primaryColumn, primaryPro, selectByExample));
//				
//				//如果存在resultmap配置则生成关系查询的sql语句
//				if(resultMap!=null && resultMap.toString().trim().length()>0){
//					resultMap.append("</resultMap>\r\n");
//					
//					//生成关系查询的sql语句
//					String relationSql = selectByPrimaryKey.toString();
//					if(relationSql!=null && !relationSql.equals("")){
//						relationSql = relationSql.replaceFirst("selectByPrimaryKey", "selectRelationByPrimaryKey");
//						relationSql = relationSql.replaceFirst("BaseResultMap", "RelationResultMap");
//						sqlStatement.append(relationSql);
//						sqlStatement.append("\r\n");
//					}
//					relationSql = selectByExample.toString();
//					if(relationSql!=null && !relationSql.equals("")){
//						relationSql = relationSql.replaceFirst("selectByExample", "selectRelationByExample");
//						relationSql = relationSql.replaceFirst("BaseResultMap", "RelationResultMap");
//						sqlStatement.append(relationSql);
//						sqlStatement.append("\r\n");
//					}
//					
//				}
//				
//				config.append(resultMap);
//				config.append(sqlStatement);
//				config.append(cusQuery);
//				config.append(updateFromMapByExample);
//				return "\r\n\r\n<!-- Extension Sql Optional -->\r\n".concat(config.toString());
//			}
//		};
//		
//		root.addElement(element);
		
		return true;
	}

	@Override
	public boolean modelFieldGenerated(Field field,
			TopLevelClass topLevelClass, IntrospectedColumn introspectedColumn,
			IntrospectedTable introspectedTable, ModelClassType modelClassType) {
		// TODO Auto-generated method stub
		super.modelFieldGenerated(field, topLevelClass, introspectedColumn,
				introspectedTable, modelClassType);
		field.setVisibility(JavaVisibility.PROTECTED);
		if(field.getType().getFullyQualifiedName().equals("java.util.Date")){
			topLevelClass.addImportedType("org.springframework.format.annotation.DateTimeFormat");
			if(introspectedColumn.getJdbcTypeName().equals("TIMESTAMP")){
				field.addAnnotation("@DateTimeFormat(pattern=\"yyyy-MM-dd HH:mm:ss.SSS\")");
			}else{
				field.addAnnotation("@DateTimeFormat(pattern=\"yyyy-MM-dd\")");
			}
		}
		
		if(field.getType().getFullyQualifiedName().equals("java.util.List")){
			field.setType(new FullyQualifiedJavaType("java.util.List<"+introspectedColumn.getProperties().get("genericType")+">"));
		}
		
		if(field.getType().getFullyQualifiedName().equals("java.math.BigDecimal")){
			topLevelClass.addImportedType("org.gm.mybatis.ext.annotation.Numberprecision");
			StringBuilder ann = new StringBuilder();
			ann.append("@Numberprecision(value=")
				.append(introspectedColumn.getLength())
				.append(", scale=")
				.append(introspectedColumn.getScale())
				.append(")");
			field.addAnnotation(ann.toString());
		}
		
		return true;
	}

	@Override
	public boolean modelGetterMethodGenerated(Method method,
			TopLevelClass topLevelClass, IntrospectedColumn introspectedColumn,
			IntrospectedTable introspectedTable, ModelClassType modelClassType) {
		// TODO Auto-generated method stub
		if(method.getReturnType().getFullyQualifiedName().equals("java.util.Date")){
			topLevelClass.addImportedType("com.fasterxml.jackson.databind.annotation.JsonSerialize");
			if(introspectedColumn.getJdbcTypeName().equals("TIMESTAMP")){
				topLevelClass.addImportedType("org.gm.mybatis.ext.util.DateTimeSerializer");
				method.addAnnotation("@JsonSerialize(using = DateTimeSerializer.class)");
			}else{
				topLevelClass.addImportedType("org.gm.mybatis.ext.util.DateSerializer");
				method.addAnnotation("@JsonSerialize(using = DateSerializer.class)");
			}
		}
		
		if(method.getReturnType().getFullyQualifiedName().equals("java.util.List")){
			method.setReturnType(new FullyQualifiedJavaType("java.util.List<"+introspectedColumn.getProperties().get("genericType")+">"));
		}
		
		if(method.getReturnType().getFullyQualifiedName().equals("java.math.BigDecimal")){
			String pn = method.getName().substring(3);
			pn = pn.substring(0, 1).toLowerCase() + pn.substring(1);
			StringBuilder line = new StringBuilder();
			line.append("if(")
				.append(pn)
				.append(" == null)return null;");
			method.addBodyLine(0, line.toString());
			line = new StringBuilder();
			line.append("this.")
				.append(pn)
				.append(" = ")
				.append(pn)
				.append(".divide(new BigDecimal(1), ")
				.append(introspectedColumn.getScale())
				.append(", BigDecimal.ROUND_HALF_UP);");
			method.addBodyLine(1, line.toString());
		}
		
		return super.modelGetterMethodGenerated(method, topLevelClass,
						introspectedColumn, introspectedTable, modelClassType);
	}

	@Override
	public boolean modelSetterMethodGenerated(Method method,
			TopLevelClass topLevelClass, IntrospectedColumn introspectedColumn,
			IntrospectedTable introspectedTable, ModelClassType modelClassType) {
		// TODO Auto-generated method stub
		if(method.getParameters().get(0).getType().getFullyQualifiedName().equals("java.util.Date")){
			topLevelClass.addImportedType("com.fasterxml.jackson.databind.annotation.JsonDeserialize");
			if(introspectedColumn.getJdbcTypeName().equals("TIMESTAMP")){
				topLevelClass.addImportedType("org.gm.mybatis.ext.util.DateTimeDeserializer");
				method.addAnnotation("@JsonDeserialize(using = DateTimeDeserializer.class)");
			}else{
				topLevelClass.addImportedType("org.gm.mybatis.ext.util.DateDeserializer");
				method.addAnnotation("@JsonDeserialize(using = DateDeserializer.class)");
			}
		}
		
		if(method.getParameters().get(0).getType().getFullyQualifiedName().equals("java.util.List")){
			String param = method.getParameters().get(0).getName();
			method.getParameters().set(0, new Parameter(new FullyQualifiedJavaType("java.util.List<"+introspectedColumn.getProperties().get("genericType")+">"), param));
		}
		
		if(method.getParameters().get(0).getType().getFullyQualifiedName().equals("java.math.BigDecimal")){
			String pn = method.getParameters().get(0).getName();
			StringBuilder line = new StringBuilder();
			line.append("if(")
				.append(pn)
				.append(" == null)return;");
			method.addBodyLine(line.toString());
			line = new StringBuilder();
			line.append("this.")
				.append(pn)
				.append(" = ")
				.append(pn)
				.append(".divide(new BigDecimal(1), ")
				.append(introspectedColumn.getScale())
				.append(", BigDecimal.ROUND_HALF_UP);");
			method.addBodyLine(line.toString());
		}
		
		return super.modelSetterMethodGenerated(method, topLevelClass,
				introspectedColumn, introspectedTable, modelClassType);
	}

	@Override
	public boolean modelBaseRecordClassGenerated(TopLevelClass topLevelClass,
			IntrospectedTable introspectedTable) {
		// TODO Auto-generated method stub
		//记录关系对象的列表
		List<String> relationFields = new LinkedList<String>();
		
		//配置表格多对一属性操作方法
		relationFields.addAll(RalationGenerator.buildManyToOneOptMethed(topLevelClass, introspectedTable));
		
		//配置表格多对一属性操作方法
		relationFields.addAll(RalationGenerator.buildOneToManyOptMethed(topLevelClass, introspectedTable));
		
		//配置表格多对多属性操作方法
		relationFields.addAll(RalationGenerator.buildManyToManyOptMethed(topLevelClass, introspectedTable));
		
		//生成关系对象列表属性
		RalationGenerator.generatRelationBlock(topLevelClass, relationFields);
		
		//读取MD5配置并MD5生成方法
		RalationGenerator.generateMd5Optional(topLevelClass, introspectedTable);
		
		return true;
	}

	@Override
	public boolean clientGenerated(Interface interfaze,
			TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
		//mapper接口继承基接口
		RalationGenerator.generateMapperExtends(interfaze, topLevelClass, introspectedTable, baseMapper);
		
		/*查询该类是否存在服务层对象,如果不存在则自动创建一个默认对象*/
		try{
			RalationGenerator.generatorDefaultService(interfaze, topLevelClass, introspectedTable, serviceProjectPath, baseService, baseServiceImpl);
		}catch(IOException ex){
			ex.printStackTrace();
		}
		
		return true;
	}
}
